Skip to content

fix(skills): retire deprecated alias facades on every host root - #5307

Merged
huangruiteng merged 5 commits into
mainfrom
codex/retire-legacy-alias-facades
Sep 30, 2026
Merged

huangruiteng merged 5 commits into
mainfrom
codex/retire-legacy-alias-facades

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

A cross-host skill import could republish deprecated loop-global-* facades beside canonical loopx-global-* skills. Installation now retires those managed alias skills on every host root and keeps one canonical skill per outcome; user-owned files remain untouched.

The retirement lives in the existing shared facade lifecycle. Claude uses that same writer, seven repeated retirement calls and the separate helper are removed, and a typed CommandFacadeSpec.alias_for follows the command catalog instead of guessing from a name prefix. The installer is a host filesystem adapter; this adds no second orchestration or TypeScript authority owner.

Invocation migration: Claude Code, Kiro and other skill-backed hosts must use /loopx-global-*. OpenCode retains independent native alias command files when legacy aliases are enabled. Catalog entries do not promise host invocation. --no-legacy-aliases omits native alias files from fresh installs and does not remove an existing OpenCode command file. No Goal execution or write authority changes.

Validation:

  • Host installer/reconciliation suites: 138 passed; maintenance ratchet plus installer suite: 86 passed. Final focused cases after type cleanup: 25 passed.
  • Real CLI upgrade and fresh-install comparison against current main: canonical file bytes match; alias skills retire; OpenCode native aliases survive; repeated install is unchanged.
  • slash-command-install-smoke, slash-command-catalog-smoke, install-local-smoke: passed.
  • Configured mypy: 19 source files passed; strict changed-module mypy: 2 files passed; Ruff, compile and diff hygiene passed.
  • Public boundary scan: six candidate paths clean. Installer Any count falls from 11 on current main to 7, with no metric ceiling increase.

Managed-file preservation, dry run, repeated install/uninstall and all eight host layouts are covered. External host applications were not launched; this qualifies installer output and filesystem lifecycle. Frontend/Lark settings do not expose these host facade files and are unchanged. Final head after integrating current main: 85 installer/discovery cases passed. Full local premerge passed all 19 selected and five direct checks with a valid exact-scope quality receipt. The first attempt had a 120-second installer timeout and a missing TypeScript dev dependency; those validation prerequisites were repaired and all checks rerun, without skipping checks or raising source metric ceilings. Review policy does not wait for remote CI.

中文:统一所有宿主的规范 skill 安装和废弃托管别名清理,删除重复分支,别名来自命令目录的显式关系。Claude/Kiro 等宿主改用 /loopx-global-*,只有 OpenCode 保留独立 native alias 文件;用户自有文件、Goal 执行与权限不变。

LoopX still materializes the deprecated /loop-global-* alias facades into
every non-Codex host root (Claude Code, OpenCode, opt-in hosts) because only
the Codex surface filtered them. A host that imports skills into a shared
root such as ~/.agents/skills then copies a deprecated facade next to the
canonical one, and the same outcome resolves twice - which is what made
loopx doctor report route conflicts for loopx-pr-review.

Every host skill root now installs one canonical facade per outcome and
retires an existing managed /loop-global-* skill file on install and
uninstall. Alias entries stay in the command catalog and in a host's own
native slash-command registry (for example OpenCode commands and Codex
prompts), a user-owned same-name skill is preserved and reported, and the
dry run keeps working through the same readback.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Characterize the new contract: the managed alias skill is retired from a
Claude Code root, a user-owned same-name skill survives, the canonical
facade is still installed, and OpenCode keeps the alias as a typed command
while its skill file is gone.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>

@cocolord cocolord left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

动机

这个 PR 解决的是一个真实且会反复出现的安装问题:Claude Code 等宿主仍发布 loop-global-* 废弃 skill facade,跨宿主导入会把它们复制进共享 skill root,使同一个全局管理结果同时出现 canonical 与 legacy 两个可发现入口。把源头收敛成每个 outcome 一个 canonical skill,确实能减少 route conflict 和后续清理成本。

不过,这个目标同时触及既有别名兼容性。严格检查不能只证明“旧文件删掉了”,还必须证明用户原来能调用的兼容入口仍存在,或者清楚披露它已被移除。目前 exact head 没有满足后半部分。

改动思路

install_slash_commands 现在把规格拆成完整 specs、只含 canonical 的 canonical_specs,以及通过名称前缀筛出的 legacy_alias_specs。Codex 复用已有退休路径;Claude Code、Gemini、Antigravity、Kiro、Cursor、ZCode 和 OpenCode 都只向 skill root 写 canonical facade,再调用 _retire_legacy_alias_skills。该 helper 继续把删除权限交给既有 _retire_managed_file:只有带 loopx-managed-slash-command:v1 marker 的文件才删除,无 marker 的用户文件返回 skipped_user_file。OpenCode 的独立 commands/*.md 仍使用完整 specs,因此它的 legacy command 得以保留。

方向上,源头停止发布重复 skill 是合理的,marker-based 删除也保持了权限边界。但共同策略目前在七个 host 分支重复调用,legacy 身份只靠 startswith("loop-global-") 推断;这两点既触发了仓库 ratchet,也把未来 alias 漏判/误判风险扩大到所有 host。

具体改动

完整 diff 包含 5 个文件、+236/-22:loopx/slash_command_install.py 是唯一生产代码;tests/test_slash_command_install.py、tests/test_skill_discovery_reconciliation.py 和 examples/slash-command-install-smoke.py 覆盖退休与所有权;docs/guides/installing-loopx.md 扩大了 host 说明。

关键代码讲解

  • _command_prompt_specs 仍生成 canonical command,并在启用兼容时追加四个 legacy spec;本 PR 新增的 legacy_alias_specs 通过字符串前缀再次分类,没有显式 alias role 或 canonical target。
  • _retire_legacy_alias_skills 解析嵌套/flat 两种 skill 路径,调用 _retire_managed_file,并把 retired_managed_file、would_retire_managed_file 或 skipped_user_file 写入安装回执。删除本身是 fail-closed 的。
  • install_slash_commands 把所有非 Codex host skill writer 改为 canonical_specs,再在七个分支分别执行 legacy retirement;OpenCode 的 command writer 继续遍历完整 specs。
  • 新增单测和 smoke 证明 managed alias 会删除、用户自有 alias 会保留、canonical skill 会存在,以及 OpenCode 的 native alias command 文件仍会存在;reconciliation 测试也改为期待 Claude 的 managed alias 被退休。

对主干的风险

阻塞项

  1. [P1] 当前 PR 自己触发了 required maintainability ratchet。 Immutable base 的 loopx/slash_command_install.py 为 1590 行、Any=11;exact head 为 1700 行、Any=13,超过 checked-in ceiling 11。远端 test-shard (3) 的唯一失败和本地复现一致:module_metric_budget:loopx/slash_command_install.py;该 shard 其余为 3314 passed、13 skipped、90 subtests passed,pytest 与 merge-gate 是它的汇总失败。这不是 base 噪声。最小修复是把 alias retirement 收进共同 facade lifecycle,消除七个重复策略调用与新增的非类型化 Any;如果维护者确实接受该增长,也应按 ratchet 提示在 module_metric_baseline.json 明确记录 reviewed ceiling 和理由,然后重跑 focused ratchet 与 required CI,不能直接忽略红灯。

  2. [P1] “所有 host 的 native slash 兼容仍在”与实际输出不符。 我用同一个 public CLI 安装请求比较了 immutable base 5ab23b3f67a2c1098717ebb450572c8158683153 和 exact head。base 会为 Claude Code 与 OpenCode 都创建 loop-global-summary skill,Claude 回执明确给出 invoke_as=["/loop-global-summary"],OpenCode 还会创建独立 command 文件;head 删除两边的 alias skill,只剩 OpenCode command。Claude Code(以及按 skill 名暴露 slash command 的 Kiro)没有第二个 registry 来承接旧名字,因此旧 invocation 实际消失。当前 PR body、运行时 note 和安装文档却都说 native compatibility 保留。请二选一:为这些 host 保留不造成重复 discovery 的原生 alias;或把兼容性声明严格限定到 OpenCode 等确有独立 registry 的 host,并明确写出其他 host 的 breaking migration,再用 host-specific tests 固化。

  3. [P2] delivery 分类不应依赖名字前缀。 str(spec["name"]).startswith("loop-global-") 是新的跨 host 策略入口。未来新增不同命名的 legacy alias 会漏退休,误用该前缀的非 alias 又会被删除。请在 spec 中加入显式 alias role/canonical target,或让 builder 返回类型化 canonical/legacy 分组,由安装与退休共同消费。

验证与边界

相关 111 个 pytest 全部通过;slash-command-install-smoke、slash-command-catalog-smoke、install-local-smoke、changed-file Ruff、Python compile 和 git diff --check 也通过。正向收益因此已验证:canonical-only skill layout 生效,managed alias 会退休,用户文件会保留,OpenCode command alias 不受影响。未启动外部 host 二进制,但生产 CLI 的 base/head 文件与 invoke_as 回执已经足以否定当前全 host 兼容性表述。

语义与 CI 对齐

改动没有扩大仓库、网络、凭据、Goal 或 merge 权限;retired_managed_file 是机器执行结果,不是“建议”。领域用语保持中立。真正未对齐的是两处:legacy/canonical delivery 仍由字符串启发式分类,以及 required module metric contract 明确拒绝当前增长。修复后应重跑 host installer suite、三个 smoke、maintainability ratchet 与 required CI。

我的整体评价

REQUEST_CHANGES exact head 26873b2e1f6e0a239abc0122dc47f8ec62418445。我认可删除跨宿主重复来源的价值,长期可维护性方向也是正向的,且关键文件所有权负路径已经验证;但当前 head 既有一项直接归因于本 PR 的 required CI failure,也对既有 host alias 兼容性作了可复现的错误披露,所以不能批准。请先关闭上述 P1,再把 alias 角色改为显式结构或至少给出有边界的类型化方案;任何新 head 都需要重新做 whole-PR evidence pass。本 review 不授予 merge 权限。

English verdict: REQUEST_CHANGES on 26873b2e1f6e0a239abc0122dc47f8ec62418445. Canonical-only skill installation, managed-file retirement, user-file preservation, and OpenCode command compatibility are validated, but the PR directly fails the maintainability ratchet (Any 11 -> 13) and its all-host native-compatibility claim is false for Claude Code and other skill-backed slash hosts. Close the CI debt, make compatibility disclosure host-specific or preserve a real native alias, and replace the prefix-only delivery classification with an explicit alias role before re-review. This review grants no merge authority.

…lias-facades

Signed-off-by: huangruiteng <huangrt01@163.com>
…alias migration

Signed-off-by: huangruiteng <huangrt01@163.com>
…lias-facades

Signed-off-by: huangruiteng <huangrt01@163.com>

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

No blocking finding remains at b8b64aa0fa9e5a0cd2decd8abe767e039e197adf. This is a fresh review of the whole six-file PR against b79bcb1949e470aac3fcee416e96f2f4c468f926, separately checking the repairs since the earlier request-changes review at 26873b2e.

动机

普通用户更新宿主 skills 时,旧的 loop-global-* 别名可能再次与规范的 loopx-global-* 一起被发现。该问题会在后续安装和跨宿主导入时重复出现。验收目标是:一次更新清理托管别名、保留规范入口和用户自有文件,重复执行不会再生成别名副本。这个 PR 完成的是安装器这一有界结果,并不代表管家自主协作的整体里程碑已经完成。

改动思路

最强的反对意见是:删除旧入口会增加 Claude/Kiro 用户的迁移成本。继续给每个宿主复制一套别名处理逻辑,则会保留长期歧义和维护成本。目录已经声明这些别名废弃;改为四个规范命令、在文档和回执给出替代入口,是明确且有界的取舍。

采用已有的 install_skill_facade 生命周期和 retire_managed_file 所有权检查。_command_prompt_specs 从命令目录投影类型化的 alias_for,不再依靠名称前缀。没有新增能力、CLI、持久化状态或第二套编排 owner。Python 保留为既有宿主文件系统适配层;这里不需要扩大为无关的 TS 迁移。

具体改动

  • slash_command_install.py:174:规范与别名由目录的显式关系区分;安装时统一构建 specs,即使关闭别名发布,也能清理已有托管 skill。
  • slash_command_files.py:142:别名分支只清理托管文件,返回 replacement_command,不声称仍可调用;规范分支沿用已有写入逻辑。
  • install_slash_commands:805:Claude 复用公共 writer,删除独立清理 helper 和七处分支重复调用。保留有实际消费者的 Codex 元数据处理与 OpenCode 原生命令文件。
  • 安装指南明确 Claude/Kiro 等 skill 宿主迁移到 /loopx-global-*。只有 OpenCode 保留独立 native alias 文件;--no-legacy-aliases 不再被描述为会删除已有原生命令。

这同时解决上一轮三个问题:重复政策、未经证实的全宿主兼容承诺、Any 指标回退。安装器从 1591 行降至 1568 行,Any 从 11 降至 7,没有提高指标上限。

对主干的风险

用同一份合成文件状态运行真实 CLI:主干仍保留托管别名,独立的“别名应消失”断言失败;当前 head 通过,同时规范 skill、用户文件、未选择宿主和 OpenCode native alias 均保持预期。八种宿主布局还覆盖预览、卸载、关闭别名发布、重复执行和非前缀目录别名。真实文件读回补足了只测新装或只看 success 回执的不足。

宿主相关整组测试 138 项通过,维护性与安装器整组 86 项通过;整合最新主干后重新执行安装/发现用例,85 项通过。计数有重叠,不作为唯一用例总数。配置 mypy 19 个文件、严格检查两个变更模块、Ruff、编译和公开边界扫描通过。最终 head 的风险预合并通过:19 项选择检查与 5 项直接检查均通过,当前范围质量回执有效,无失败、跳过或人工阻塞。

最初预合并的 local-install smoke 超过 120 秒,语义扫描缺少仓库 TypeScript 开发依赖。恢复所需 npm 依赖、给已独立通过的安装检查 300 秒后重跑;其间最新主干安装优化进入本分支,重新记录当前范围质量回执。保留原失败原因,未跳过检查、未调高源代码指标上限。按配置只使用本地验证,不等待 GitHub CI。

实际宿主应用未启动;验证边界是生产 CLI、安装脚本和真实文件系统。Claude/Kiro 旧别名用户需要规范命令迁移,这是已披露的残余影响。前端/Lark 设置不管理这些宿主 facade 文件,因此没有对应 UI 改动。

我的整体评价

修复贴合现有所有者,删除了重复知识,迁移承诺与实现一致。后续安装/重试保持规范入口可用,用户自有内容有实际保护证据。对这一安装器修复给出批准结论;不把文件清理扩大解释为宿主模型调用或完整管家协作验收。

语义与 CI 对齐

复用目录的废弃关系与已有托管文件规则;维护性上限保持原值。真实 base/head 对照验证预期行为变化,未把历史缺陷当成必须保持的兼容承诺。检查缺失依赖和执行时间属于本地验证条件,恢复后须全部通过才合并。

English verdict: APPROVE — b8b64aa0fa9e5a0cd2decd8abe767e039e197adf uses the shared managed-file lifecycle, accurately discloses canonical invocation migration, and has verified real CLI ownership, upgrade and replay behavior.

@huangruiteng
huangruiteng merged commit 80c75dd into main Sep 30, 2026
5 checks passed
@huangruiteng
huangruiteng deleted the codex/retire-legacy-alias-facades branch September 30, 2026 12:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants